///////////////////////////////////////////////////////////////////////
// File:	EventSystem.cpp
//
// Author: Roberto Rubiano
// 
// Purpose: function definitions
///////////////////////////////////////////////////////////////////////
#include "EventSystem.h"
#include <utility>
#include <iostream>
using namespace std;

// Private Functions
void EventSystem::DispatchEvent(CEvent* pEvent)
{
	//	Make an iterator that will iterate all of our clients that
	//	should be receiveing this event
	pair<multimap<EVENTS,IListener*>::iterator,
		multimap<EVENTS,IListener*>::iterator> Range;

	Range = m_Clients.equal_range((EVENTS)pEvent->GetEventID());

	//	Go through the list of clients that are able to receive this event.
	for(multimap<EVENTS, IListener*>::iterator Iter = Range.first;
					Iter != Range.second; Iter++)
	{
		//	Pass this event to the client
		(*Iter).second->HandleEvent(pEvent);
	}
}

bool EventSystem::AlreadyRegistered(EVENTS eventID, IListener* pClient)
{
	bool bAllreadyRegistered = false;

	//	Make an iterator that will iterate all of our clients that
	//	should be receiveing this event
	pair<multimap<EVENTS,IListener*>::iterator,
		multimap<EVENTS,IListener*>::iterator> Range;

	//	Find all of the clients that are able to receive this event.
	Range = m_Clients.equal_range(eventID);

	for(multimap<EVENTS, IListener*>::iterator Iter = Range.first;
					Iter != Range.second; Iter++)
	{
		//	Pass this event to the client
		if((*Iter).second == pClient)
		{
			bAllreadyRegistered = true;
			break;
		}
	}

	return bAllreadyRegistered;
}

// Public Functions

EventSystem* EventSystem::GetInstance(void)
{
	static EventSystem Instance;
	return &Instance;
}

//	This adds a client to the database.  This will make new "buckets" if necessary and then
//	add the client to that given bucket.
void EventSystem::RegisterClient(EVENTS EVENTS, IListener* pClient)
{
	if(!pClient || AlreadyRegistered(EVENTS,pClient))
		return;

	m_Clients.insert(make_pair(EVENTS,pClient));
}

//	Unregisters the client for the specified event only
void EventSystem::UnregisterClient(EVENTS eventID, IListener* pClient)
{
	//	Make an iterator that will iterate all of our clients that
	//	should be receiveing this event
	pair<multimap<EVENTS,IListener*>::iterator,
		multimap<EVENTS,IListener*>::iterator> Range;

	//	Find all of the clients that are able to receive this event.
	Range = m_Clients.equal_range(eventID);

	for(multimap<EVENTS, IListener*>::iterator Iter = Range.first;
					Iter != Range.second; Iter++)
	{
		//	Pass this event to the client
		if((*Iter).second == pClient)
		{
			Iter = m_Clients.erase(Iter);
			break;
		}
	}
}

//	Removes the client from the database entirely
void EventSystem::UnregisterClientAll(IListener* pClient)
{
	multimap<EVENTS, IListener*>::iterator iter = m_Clients.begin();

	while(iter != m_Clients.end())
	{
		if((*iter).second == pClient)
		{
			iter = m_Clients.erase(iter);
		}
		else
			iter++;
	}

}

//	Sends an event to be processed later on.
void EventSystem::SendEvent(EVENTS EVENTID, void* pData)
{

	CEvent Event(EVENTID, pData);
	// Push the event into the list
	m_CurrEvents.push_back(Event);
}

//	Processes all events in our event list.
void EventSystem::ProcessEvents(void)
{
	//	Go through my list of events that are waiting to be processed.
	while(m_CurrEvents.size())
	{
		DispatchEvent(&m_CurrEvents.front());
		m_CurrEvents.pop_front();
	}
}

//	Clears all pending events
void EventSystem::ClearEvents(void)
{
	m_CurrEvents.clear();
}

//	Unregisters all objects
void EventSystem::ShutdownEventSystem(void)
{
	ClearEvents();
	m_Clients.clear();
}